package com.zipking.cloud.springbootmybatis.controller;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.google.common.collect.Maps;
import com.zipking.cloud.springbootmybatis.config.ApiCoreFactory;
import com.zipking.cloud.springbootmybatis.persistance.service.IMsgLogExtService;
import com.zipking.cloud.springbootmybatis.prop.DbConf;
import com.zipking.cloud.springbootmybatis.prop.DbProperties;
import com.zipking.cloud.springbootmybatis.service.BaseService;
import com.zipking.cloud.springbootmybatis.service.IMsgLogService;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;

@RestController
@RequestMapping(value = "/api")
public class ApiController {
    @Autowired
     private  DbProperties dbProperties;
    @Autowired
    private DbConf dbConf;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IMsgLogExtService msgLogService;
    @PostMapping(value = "/gateway")
    public String gateway(String method) {
        String password = dbProperties.getPassword();
        // 最朴实无华的参数校验

        if(StringUtils.isEmpty(method)) {
            return "fail";
        }
        BaseService service = ApiCoreFactory.getBaseService(method);
        if(ObjectUtils.isNull(service)) {
            return "没找到对应的method";
        }
        return service.execute();
    }


    @PostMapping("/sign")
    public Object sign(Long userId) {
        //1. 获取登录用户

        //2. 获取日期
        LocalDateTime now = LocalDateTime.now();
        //3. 拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = "userKey" + userId + keySuffix;
        //4. 获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        //5. 写入redis setbit key offset 1
        redisTemplate.opsForValue().setBit(key, dayOfMonth -1, true);
        return "ok";
    }
    @GetMapping("/signCount")
    public Object signCount(Long userId) {
        //1. 获取登录用户

        //2. 获取日期
        LocalDateTime now = LocalDateTime.now();
        //3. 拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = "userKey" + userId + keySuffix;
        //4. 获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        //5. 获取本月截至今天为止的所有的签到记录，返回的是一个十进制的数字 BITFIELD sign:5:202301 GET u3 0
        List<Long> result = redisTemplate.opsForValue().bitField(
                key,
                BitFieldSubCommands.create()
                        .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
        //没有任务签到结果
        if (result == null || result.isEmpty()) {
            return 0;
        }
        Long num = result.get(0);
        if (num == null || num == 0) {
            return 0;
        }
        //6. 循环遍历
        int count = 0;
        while (true) {
            //6.1 让这个数字与1 做与运算，得到数字的最后一个bit位 判断这个数字是否为0
            if ((num & 1) == 0) {
                //如果为0，签到结束
                break;
            } else {
                count ++;
            }
            num >>>= 1;
        }
        return count;
    }

@Autowired
    RestTemplate restTemplate;

    @GetMapping("/{id}")
    public Callable<Map> allInfo(@PathVariable("id") Long id) throws Exception {
        System.out.printf("请求开始: %d%n", System.currentTimeMillis()) ;
       Map<@Nullable String, @Nullable Object> map = Maps.newHashMap();
        CompletableFuture<Map> scoreFuture = CompletableFuture
                .supplyAsync(() -> this.restTemplate.getForObject("http://localhost:8080/api/scores/{id}", Map.class, id))
                .exceptionally(ex -> (Map) map.put("data", String.format("接口发生异常: %s", ex.getMessage()))) ;

        CompletableFuture<Map> orderFuture = CompletableFuture
                .supplyAsync(() -> this.restTemplate.getForObject("http://localhost:8080/api/orders/{id}", Map.class, id))
                .exceptionally(ex -> (Map) map.put("data", String.format("接口发生异常: %s", ex.getMessage()))) ;

        CompletableFuture<Map> tradeFuture = CompletableFuture
                .supplyAsync(() -> this.restTemplate.getForObject("http://localhost:8080/api/trades/{id}", Map.class, id))
                .exceptionally(ex ->(Map) map.put("data", String.format("接口发生异常: %s", ex.getMessage()))) ;

        Callable<Map> cb = () -> {
            CompletableFuture.allOf(scoreFuture, orderFuture, tradeFuture).join() ;
            //return Map.of("score", scoreFuture.get(), "order", orderFuture.get(), "trade", tradeFuture.get()) ;
            System.out.println(scoreFuture.get());
            System.out.println(orderFuture.get());
            System.out.println(tradeFuture.get());
            return (Map) map.put("ok",scoreFuture.get());
        } ;
        System.out.printf("请求结束: %d%n", System.currentTimeMillis()) ;
        return cb  ;
    }


    @GetMapping("/scores/{id}")
    public Map scores(@PathVariable("id") Long id) {
        System.out.printf("scores:"+id);
         Map<@Nullable String, @Nullable Object> resultMap = Maps.newHashMap();
        resultMap.put("scores",id);
        return resultMap;
    }
    @GetMapping("/orders/{id}")
    public Map orders(@PathVariable("id") Long id) {
        System.out.printf("orders:"+id);
        Map<@Nullable String, @Nullable Object> resultMap = Maps.newHashMap();
        resultMap.put("orders",id);
        return resultMap;
    }
    @GetMapping("/trades/{id}")
    public Map trades(@PathVariable("id") Long id) {
        System.out.printf("trades:"+id);
        Map<@Nullable String, @Nullable Object> resultMap = Maps.newHashMap();
        resultMap.put("trades",id);
        return resultMap;
    }

    @GetMapping("/mapperSaveBatch")
    public Object mapperSaveBatch() {
       msgLogService.updateBatchMsgLog();
        return "OK";
    }
}
